package Algoritmo;

import Clases.Arbol;
import Clases.Arbol.O;
import Clases.Espacio;
import Clases.Arbol.T;
import Clases.Tablero;
import Clases.Tablero.Estado;
import Clases.Posicion;
import Clases_Auxiliares.DistanciaTiempo;
import Interfaz.TableroJuego;

public class Cromosoma {
	Arbol arbol;
	double f;
	double puntuacion;
	double puntuacion_acu;
	int profundidadMin;
	int profundidadMax;
	int numPartidas;
	int penalizacion;
	Posicion alien;
	Posicion defensor;
	int numPartidasGanadas;
	
	public Cromosoma(){}
	
	public Cromosoma(int profundidadMin,int profundidadMax,int numPartidas,int penalizacion){
		this.profundidadMin = profundidadMin;
		this.profundidadMax = profundidadMax;
		this.numPartidas = numPartidas;
		this.penalizacion = penalizacion;
		this.numPartidasGanadas = 0;
	}
	
	//region Métodos Públicos
	public void inicializacion(){
		arbol = Arbol.crearArabol(arbol, profundidadMin, profundidadMax);
		f = adaptacion();
	}
	
	public int getNumNodos(){
		return arbol.getNumNodos();
	}
	
	public Arbol getSubArbol(int nodo){
		return Arbol.getSubArbol(arbol,nodo);
	}
	
	public Cromosoma clone(){
		Cromosoma c = new Cromosoma(profundidadMin,profundidadMax,numPartidas,penalizacion);
		c.f = f;
		c.puntuacion = puntuacion;
		c.puntuacion_acu = puntuacion_acu;
		c.arbol = arbol.clone();
		c.alien = alien!=null ? alien.clone() : null;
		c.defensor = defensor!= null ? defensor.clone() : null;
		c.numPartidasGanadas = numPartidasGanadas;
		return c;
	}
	
	public String toString(){
		return arbol.toString();
	}
	
	public void setAdaptacion(){
		numPartidasGanadas = 0;
		f = adaptacion();
	}
	
	public void recalcularNumNodos(){
		Arbol.recalcularNumNodos(arbol);
	}
	//endregion
	
	//region Gets y Sets
	public Arbol getArbol() {
		return arbol;
	}

	public void setArbol(Arbol arbol) {
		this.arbol = arbol;
	}

	public double getF() {
		return f;
	}

	public void setF(int f) {
		this.f = f;
	}
	
	public double getPuntuacion() {
		return puntuacion;
	}

	public void setPuntuacion(double puntuacion) {
		this.puntuacion = puntuacion;
	}

	public double getPuntuacion_acu() {
		return puntuacion_acu;
	}

	public void setPuntuacion_acu(double puntuacion_acu) {
		this.puntuacion_acu = puntuacion_acu;
	}

	public int getProfundidadMax() {
		return profundidadMax;
	}
	
	public void setProfundidadMax(int profundidadMax) {
		this.profundidadMax = profundidadMax;
	}
	
	public int getProfundidadMin() {
		return profundidadMin;
	}
	
	public void setProfundidadMin(int profundidadMin) {
		this.profundidadMin = profundidadMin;
	}
	
	public int getNumPartidas() {
		return numPartidas;
	}
	
	public void setNumPartidas(int numPartidas) {
		this.numPartidas = numPartidas;
	}
	
	public int getPenalizacion() {
		return penalizacion;
	}
	
	public void setPenalizacion(int penalizacion) {
		this.penalizacion = penalizacion;
	}
	
	public Posicion getAlien() {
		return alien;
	}
	
	public void setAlien(Posicion alien) {
		this.alien = alien;
	}
	
	public Posicion getDefensor() {
		return defensor;
	}
	
	public void setDefensor(Posicion defensor) {
		this.defensor = defensor;
	}
	
	public int getNumPartidasGanadas() {
		return numPartidasGanadas;
	}
	
	public void setNumPartidasGanadas(int numPartidasGanadas) {
		this.numPartidasGanadas = numPartidasGanadas;
	}
	//endregion

	//region Función de adaptación
	public double adaptacion(){
		Espacio espacio = new Espacio(20);
		int adaptacion = 0;
		int tiempo,tiempo_anterior;
		int distancia, nueva_distancia = 0;
		boolean[] termina = {false,false};
		Posicion a = null;
		Posicion d = null;
		for (int np = 0;np < numPartidas; np++){
			tiempo = 0;
			distancia = 0;
			espacio.inicializarEspacio();
			d = espacio.getDefensor().clone();
			a = espacio.getAlien().clone();
			termina = espacio.terminacion();
			DistanciaTiempo dt = new DistanciaTiempo(distancia,tiempo);
			while (!termina[0]){
				tiempo_anterior = tiempo;
				evaluar(arbol,espacio,dt);
				tiempo = dt.getTiempo();
				if (tiempo_anterior == tiempo){
					tiempo = tiempo + 1;
					nueva_distancia = espacio.avanzarTiempo();
					distancia = distancia + nueva_distancia;
				}else{
					distancia = distancia + dt.getDistancia();
				}
				dt.setDistancia(0);
				termina = espacio.terminacion();
			}
			adaptacion = adaptacion + distancia;
			if(!termina[1]){
				if (!espacio.isSeDisparoMisil()) adaptacion = adaptacion + 50;
				adaptacion = adaptacion + penalizacion;
			}else{
				alien = a;
				defensor = d;
				numPartidasGanadas = numPartidasGanadas + 1;
				//adaptacion = adaptacion - 10000;
			}
		}
		return adaptacion;
	}
	//endregion
	
	//region Función de evaluación de una arbol
	private int evaluar(Arbol arbol,Espacio espacio,DistanciaTiempo dt){
		int valor1 = 0;
		int valor2 = 0;
		int valor3 = 0;
		int nueva_distancia = 0;
		T t = arbol.getTerminal();
		O o = arbol.getOperador();
		if(arbol.isHoja()){
			if (t == T.FUEGO){
				if (!espacio.isHayMisil()){
					espacio.setHayMisil(true);
					espacio.setPosicionMisil(espacio.getDefensor().getX()-1,espacio.getDefensor().getY());
					espacio.setSeDisparoMisil(true);
				}
				dt.avanzarTiempo();
				nueva_distancia = espacio.avanzarTiempo();
				dt.aumentarDistacia(nueva_distancia);
			}else if (t == T.IZQUIERDA){
				int y = espacio.getDefensor().getY();
				if(y > 0) espacio.setPosicionDefensor(espacio.getDefensor().getX(),y-1);
				dt.avanzarTiempo();
				nueva_distancia = espacio.avanzarTiempo();
				dt.aumentarDistacia(nueva_distancia);
			}else if (t == T.DERECHA){
				int y = espacio.getDefensor().getY();
				if(y < (espacio.getTamTablero() - 1) ) espacio.setPosicionDefensor(espacio.getDefensor().getX(),y + 1);
				dt.avanzarTiempo();
				nueva_distancia = espacio.avanzarTiempo();
				dt.aumentarDistacia(nueva_distancia);
			}else if (t == T.DIST_Y){
				valor1 = espacio.getAlien().getX();
				return valor1;
			}else if (t == T.DIST_X){
				valor1 = Math.abs(espacio.getDefensor().getY() - espacio.getAlien().getY());
				if (espacio.seAlejanAlienDefensor()) valor1 = - valor1;
				return valor1;
			}
		}else{
			if (o == O.IF){
				valor1 = evaluar(arbol.getHijoIzq(),espacio,dt);
				if (!espacio.isTermina()){
					if (valor1 != 0) return evaluar(arbol.getHijoCen(),espacio,dt);
					else return evaluar(arbol.getHijoDer(),espacio,dt);
				}
			}else if (o == O.PROGN2){
				valor1 = evaluar(arbol.getHijoIzq(),espacio,dt);
				if (!espacio.isTermina()){
					valor2 = evaluar(arbol.getHijoDer(),espacio,dt);
					return valor1 + valor2;
				}
			}else if (o == O.PROGN3){
				valor1 = evaluar(arbol.getHijoIzq(),espacio,dt);
				if (!espacio.isTermina()){
					valor2 = evaluar(arbol.getHijoCen(),espacio,dt);
					if (!espacio.isTermina()){
						valor3 = evaluar(arbol.getHijoDer(),espacio,dt);
						return valor1 + valor2 + valor3;
					}
				}
			}else if (o == O.EQ){
				valor1 = evaluar(arbol.getHijoIzq(),espacio,dt);
				if (!espacio.isTermina()){
					valor2 = evaluar(arbol.getHijoDer(),espacio,dt);
					if (valor1 == valor2) return 1;
					else return 0;
				}
			}
		}
		return 0;
	}
	//endregion
	
	public static void main(String[] args){
		Cromosoma c = new Cromosoma(2,3,30,200);
		c.arbol = null;
		c.arbol = Arbol.crearArabol(c.arbol,c.getProfundidadMin(), c.getProfundidadMax());
		Arbol.recalcularNumNodos(c.arbol);
	}

	public Espacio getEspacioSimulacion() {
		if (alien == null || defensor == null) return null;
		Espacio espacio = new Espacio(20);
		espacio.crearEspacio(alien.clone(), defensor.clone());
		return espacio;
	}
	
	public Espacio getEspacioSimulacionAzar() {
		if (alien == null || defensor == null) return null;
		Espacio espacio = new Espacio(20);
		espacio.inicializarEspacio();
		//espacio.crearEspacio(alien., defensor.clone());
		return espacio;
	}
}
